#include "soft_iic.h"



static void soft_iic_start(soft_iic_struct *soft_iic)
{	
    /* SCL为高电平时, SDA由1变为0 */
    soft_iic->pfn_scl_set(1);
    soft_iic->pfn_sda_set(1);
    soft_iic->pfn_usdelay(5); 	    /* 高电平时间大于4.7us */
    soft_iic->pfn_sda_set(0);
    soft_iic->pfn_usdelay(5); 		/* 低电平时间大于4us */
    soft_iic->pfn_scl_set(0);	    
    
    soft_iic->pfn_sda_set(1);       /* 释放总线 */
}


static void soft_iic_stop(soft_iic_struct *soft_iic)
{
    /* SCL为高电平时, SDA由0变为1 */
    soft_iic->pfn_scl_set(1);
    soft_iic->pfn_sda_set(0);
    soft_iic->pfn_usdelay(5); 	 	 /* 高电平时间大于4.7us */
    soft_iic->pfn_sda_set(1);
    soft_iic->pfn_usdelay(5); 		 /* 低电平时间大于4us */
}

static uint8_t soft_iic_get_ack(soft_iic_struct *soft_iic)
{
    
    uint8_t result = 0;

    soft_iic->pfn_scl_set(0);
    soft_iic->pfn_sda_set(1);	    /* 拉高总线 */

    
    soft_iic->pfn_scl_set(0);       /* 主机产生一个时钟 */
    soft_iic->pfn_usdelay(5); 	           
    soft_iic->pfn_scl_set(1); 
    soft_iic->pfn_usdelay(5); 	    /* 高电平要大于4.7us */

    result = soft_iic->pfn_sda_get() ? 1 : 0; 

    soft_iic->pfn_scl_set(0);
    
    return result;
}

static void soft_iic_put_ack(soft_iic_struct *soft_iic, uint8_t ack)
{
    soft_iic->pfn_sda_set(ack);
    
    soft_iic->pfn_usdelay(5); 
    soft_iic->pfn_scl_set(1); 
    soft_iic->pfn_usdelay(5);       /* 高电平要大于4.7us */
    soft_iic->pfn_scl_set(0);	
    soft_iic->pfn_usdelay(1); 
    
    soft_iic->pfn_sda_set(1) ;      /* 释放总线 */
    
}

static void soft_iic_write_byte(soft_iic_struct *soft_iic, uint8_t data)
{
    uint8_t i = 0;

    soft_iic->pfn_scl_set(0);       /* SCL低电平期间SDA可以改变 */
    soft_iic->pfn_usdelay(5); 
    
    for(i = 0;i<8;i++)
    {
        soft_iic->pfn_sda_set((data >> 7) & 0x01);
        data = data << 1;
        soft_iic->pfn_usdelay(5); 
        soft_iic->pfn_scl_set(1);
        soft_iic->pfn_usdelay(5);
        soft_iic->pfn_scl_set(0);
        soft_iic->pfn_usdelay(5); 
    }	
    
    soft_iic->pfn_sda_set(1) ;     /* 释放总线 */
}

static void soft_iic_read_byte(soft_iic_struct *soft_iic, uint8_t* data)
{
    uint8_t i   = 0;
    uint8_t tmp = 0;
    
    soft_iic->pfn_scl_set(0);      /* SCL低电平期间SDA可以改变 */
    soft_iic->pfn_usdelay(5);
    
    for(i = 0;i<8;i++)
    {
        tmp = tmp << 1;
        soft_iic->pfn_sda_set(1);  /* 拉高总线 */
        soft_iic->pfn_usdelay(5); 
        soft_iic->pfn_scl_set(1);  /* soft_iic->pfn_scl_set() =1时,SDA稳定 */
        soft_iic->pfn_usdelay(5); 
        
        if(soft_iic->pfn_sda_get()) 
        {
            tmp |= 0x01;
        }
        else 
        {
            tmp &= (~0x01);
        }
        
        soft_iic->pfn_scl_set(0);  /* SCL低电平期间SDA可以改变 */
        soft_iic->pfn_usdelay(5); 
    }
    
    soft_iic->pfn_sda_set(1);      /* 释放总线 */

    *data = tmp;
}

uint8_t soft_iic_puts(soft_iic_struct *soft_iic, 
                      uint8_t          slave_addr, 
                      uint8_t          reg_addr,
                      uint8_t         *p_data,
                      uint8_t          len)
{
    uint8_t i   = 0;
    
    slave_addr &= 0xfe;	                        /* 确保最低位为0 */
    soft_iic_start(soft_iic); 	                /* 发送起始信号 */
    soft_iic_write_byte(soft_iic, slave_addr);  /* 发送从机地址 */
    
    if(soft_iic_get_ack(soft_iic))
    {
        soft_iic_stop(soft_iic);
        return 1;		
    }
    
    /* 发送子地址 */
    soft_iic_write_byte(soft_iic, reg_addr);   
    if(soft_iic_get_ack(soft_iic))
    {
        soft_iic_stop(soft_iic);
        return 1;		
    }	

    /* 发送数据 */
    for(i=0; i<len; i++)
    {
        soft_iic_write_byte(soft_iic, *p_data++);
        if(soft_iic_get_ack(soft_iic))
        {
            soft_iic_stop(soft_iic);
            return 1;		
        }
    }

    /* 发送完成 */
    soft_iic_stop(soft_iic);

    return 0;

}

uint8_t soft_iic_gets(soft_iic_struct *soft_iic,
                      uint8_t          slave_addr,
                      uint8_t          reg_addr,
                      uint8_t         *p_data,
                      uint8_t          len)
{
    uint8_t    i = 0;

    slave_addr &= 0xfe;	                        /* 确保最低位为0 */
    soft_iic_start(soft_iic); 	                /* 发送起始信号 */
    soft_iic_write_byte(soft_iic, slave_addr);  /* 发送从机地址 */
    
    if(soft_iic_get_ack(soft_iic))
    {
        soft_iic_stop(soft_iic);
        return 1;		
    }

    /* 发送子地址 */
    soft_iic_write_byte(soft_iic, reg_addr);
    if(soft_iic_get_ack(soft_iic))
    {
        soft_iic_stop(soft_iic);
        return 1;		
    }	

    /* 发送重复起始信号 */
    soft_iic_start(soft_iic);
    
    /* 发送从机地址 */
    soft_iic_write_byte(soft_iic, slave_addr|0x01);
    if(soft_iic_get_ack(soft_iic))
    {
        soft_iic_stop(soft_iic);
        return 1;		
    }
    
    /* 发送数据 */
    for(i=0; i<len; i++)
    {
        soft_iic_read_byte(soft_iic, p_data++);
        
        if(i == (len-1))
        {
            soft_iic_put_ack(soft_iic, 1);	/* 发送非应答 */
        }
        else
        {
            soft_iic_put_ack(soft_iic, 0);	/* 发送应答 */
        }
    }

    /* 接收完毕 */
    soft_iic_stop(soft_iic);

    return 0;

}

int soft_iic_init(soft_iic_struct *soft_iic)
{
    if((soft_iic->pfn_scl_set == NULL) || 
       (soft_iic->pfn_sda_get == NULL) || 
       (soft_iic->pfn_sda_set == NULL) || 
       (soft_iic->pfn_usdelay == NULL))
    {
        return -1;
    }
    
    soft_iic->pfn_scl_set(1);
    soft_iic->pfn_sda_set(1);	
    soft_iic->pfn_usdelay(10);
    
    return 0;
}


